package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Slf4j
@Component
@Aspect
public class AutoFillAspect {

    @Pointcut("execution(* com.sky.mapper..*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void pointCut(){};

    @Before("pointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始填充公共参数...");
        //获取方法的签名,signature是原始签名,要拿到方法需要强转
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //获取到被代理的方法
        Method method = methodSignature.getMethod();
        //获取注解进行判断
        OperationType operationType = method.getAnnotation(AutoFill.class).value();
        //需要填充的时间
        LocalDateTime now = LocalDateTime.now();
        //需要填充的操作人id
        Long currentId = BaseContext.getCurrentId();
        //获取执行方法的参数并做健壮性判断
        Object arg = joinPoint.getArgs()[0];
        if (arg == null){
            //如果参数为空则直接返回
            return;
        }

        try {
            //不知道获取到的参数具体是哪个实体类,但是所有作为参数的实体类中都存在着写名称的方法,通过反射根据方法名获取到这些方法,并执行赋值
            Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //不论更新或者新增都需要设置更新时间和操作人id
            if (OperationType.INSERT.equals(operationType)){
                //如果是新增操作则需要多添加两个字段
                Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                setCreateTime.invoke(arg,now);
                setCreateUser.invoke(arg,currentId);
            }
            setUpdateTime.invoke(arg,now);
            setUpdateUser.invoke(arg,currentId);
        } catch (Exception e) {
            log.info("自动填充失败...",e);
        }
    }
}
